package com.mutual.assistance.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.mutual.assistance.exception.BizException;
import com.mutual.assistance.exception.code.ExceptionCode;
import com.mutual.assistance.user.converter.UserConverterParams;
import com.mutual.assistance.user.mapper.PermissionMapper;
import com.mutual.assistance.user.mapper.RoleMapper;
import com.mutual.assistance.user.model.dto.MenuDTO;
import com.mutual.assistance.user.model.dto.MenusDTO;
import com.mutual.assistance.user.model.dto.RoleDTO;
import com.mutual.assistance.user.model.po.PermissionPO;
import com.mutual.assistance.user.model.po.RolePO;
import com.mutual.assistance.user.model.vo.AddPermissionVO;
import com.mutual.assistance.user.model.vo.AddPermissionsVO;
import com.mutual.assistance.user.model.vo.AddRoleVO;
import com.mutual.assistance.user.model.vo.UpdateRoleVO;
import com.mutual.assistance.user.service.AuthorityMenuService;
import com.mutual.assistance.user.service.AuthorityRoleService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenyuxin
 * @version 1.0
 * @description 权限服务实现类
 * @date 2023/4/19 13:12
 */
@Service
@Slf4j
public class AuthorityRoleServiceImpl implements AuthorityRoleService {

    @Resource
    private UserConverterParams authConverterParams;

    @Resource
    private AuthorityRoleService authorityRoleService;

    @Resource
    private AuthorityMenuService authorityMenuService;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private PermissionMapper permissionMapper;


    @Transactional
    @Override
    public void addRoleAndMenu(AddRoleVO addRoleVO) {
        log.info("请求的参数：{}", addRoleVO);
        String roleCode = addRoleVO.getRoleCode();
        RolePO rolePODB = roleMapper.selectOne(new LambdaQueryWrapper<RolePO>()
                .eq(RolePO::getRoleCode, roleCode));
        if (rolePODB != null) {
            log.info("数据库中已经存在该角色记录，roleId：{} 与 roleCode：{}", rolePODB.getId(), roleCode);
            throw new BizException(ExceptionCode.REPEAT_ADDITION.getCode(), ExceptionCode.REPEAT_ADDITION.getMsg());
        }

        RolePO rolePO = authConverterParams.rolePO2AddRoleVO(addRoleVO);
        log.info("转换后参数：{}", rolePO);
        int insert = roleMapper.insert(rolePO);
        if (insert < 0) {
            log.error("插入角色失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(), ExceptionCode.SQL_EX.getMsg());
        }

        List<String> menusId = addRoleVO.getMenusId();

        if (menusId == null) {
            return;
        }

        RolePO rolePODBNew = roleMapper.selectOne(new LambdaQueryWrapper<RolePO>()
                .eq(RolePO::getRoleCode, roleCode));

        log.info("资源列表id：{}", menusId);
        for (String menuId : menusId) {
            addMenuForRole(rolePODBNew.getId().toString(), menuId);
        }
    }


    @Transactional
    @Override
    public void addMenuForRole(AddPermissionVO addPermission) {
        addMenuForRole(addPermission.getRoleId(), addPermission.getMenuId());
    }


    private void addMenuForRole(String roleId, String menuId) {
        log.info("输入参数：{} 与 {}", roleId, menuId);
        MenusDTO menusDTO = authorityMenuService.recursionGetMenus(menuId);
        if (CollectionUtils.isEmpty(menusDTO.getMenuDTOList())) {
            log.info("该资源没有子菜单");
            addOneMenuForRole(roleId, menusDTO.getId());
            return;
        }
        addMenAndChildMenuForRoleRecursion(roleId, menusDTO);
    }

    @Override
    @Transactional
    public void addMenusForRole(AddPermissionsVO addPermissionsVO) {
        String roleId = addPermissionsVO.getRoleId();
        log.info("添加权限的角色id为：{}", roleId);
        // 校验角色是否存在
        checkRoleIsExist(roleId);
        List<String> menusId = addPermissionsVO.getMenusId();
        if (CollectionUtils.isEmpty(menusId)) {
            log.info("没有资源id，无需添加");
            return;
        }
        for (String menuId : menusId) {
            // 校验菜单是否存在
            log.info("添加权限id为：{}", menuId);
            checkMenuIsExist(menuId);
            addMenuForRole(roleId, menuId);
        }
    }

    @Transactional
    @Override
    public void deleteRoleAndMenus(String roleId) {
        log.info("要删除的角色id：");
        checkRoleIsExist(roleId);
        int delete = roleMapper.deleteById(roleId);
        if (delete < 0) {
            log.error("删除角色失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "roleId: {}", roleId);
        }
        log.info("删除的角色记录数：{}", delete);
        deleteRolePermission(roleId);
    }

    private void deleteRolePermission(String roleId) {
        int deletePermission = permissionMapper.delete(new LambdaQueryWrapper<PermissionPO>()
                .eq(PermissionPO::getRoleId, roleId));
        if (deletePermission < 0) {
            log.error("删除角色相关权限失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "roleId: {}", roleId);
        }
        log.info("删除的角色权限数：{}", deletePermission);
    }

    @Override
    public void deleteRolesAndMenus(List<String> roleIds) {
        log.info("删除的角色id集合为：{}", roleIds);
        for (String roleId : roleIds) {
            authorityRoleService.deleteRoleAndMenus(roleId);
        }
    }

    @Override
    public void updateRoleAndPermission(UpdateRoleVO updateRoleVO) {
        // 更新角色
        log.info("获取到请求参数：{}", updateRoleVO);
        String roleId = updateRoleVO.getRoleId();
        checkRoleIsExist(roleId);
        RolePO rolePO = authConverterParams.updateRoleVO2RolePO(updateRoleVO);
        int update = roleMapper.update(rolePO, new LambdaQueryWrapper<RolePO>().eq(RolePO::getId, roleId));
        if (update < 0) {
            log.error("更新失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "roleId: {}", roleId);
        }
        log.info("更新数：{}", update);
    }

    @Override
    public RoleDTO getRole(String roleId) {
        RolePO rolePO = checkRoleIsExist(roleId);
        return getRoleNotMenuPermission(rolePO);
    }

    @NotNull
    private RoleDTO getRoleNotMenuPermission(RolePO rolePO) {
        log.info("开始转换");
        RoleDTO roleDTO = authConverterParams.rolePO2RoleDTO(rolePO);
        log.info("转换完成：{}", roleDTO);
        List<PermissionPO> permissionPOs = permissionMapper.selectList(new LambdaQueryWrapper<PermissionPO>()
                .eq(PermissionPO::getRoleId, roleDTO.getId()));
        if (CollectionUtils.isEmpty(permissionPOs)) {
            log.info("该角色没有任何权限");
            return roleDTO;
        }
        log.info("该角色的权限：{}", permissionPOs);
        List<MenuDTO> list = new ArrayList<>();
        for (PermissionPO permissionPO : permissionPOs) {
            MenuDTO menu = authorityMenuService.getMenu(permissionPO.getMenuId());
            if (menu.getIsMenu() == 0) {
                list.add(menu);
            }
        }
        roleDTO.setMenuDTOList(list);
        return roleDTO;
    }

    @Override
    public List<RoleDTO> getAllRole() {
        List<RoleDTO> list = new ArrayList<>();
        List<RolePO> rolePOs = roleMapper.selectList(new LambdaQueryWrapper<RolePO>().eq(RolePO::getStatus, 1));
        log.info("获取到角色：{}", rolePOs);
        for (RolePO rolePO : rolePOs) {
            RoleDTO roleDTO = getRoleNotMenuPermission(rolePO);
            log.info("获取到的角色权限：{}", roleDTO);
            list.add(roleDTO);
        }
        return list;
    }


    @Override
    @Transactional
    public void addOneMenuForRole(AddPermissionVO addPermissionVO) {
        addOneMenuForRole(addPermissionVO.getRoleId(), addPermissionVO.getMenuId());
    }

    private void addOneMenuForRole(String roleId, String menuId) {
        log.info("输入参数：{} 与 {}", roleId, menuId);

        // 参数判断
        if (roleId == null || menuId == null) {
            log.debug("参数不足：roleId：{} 与 menuId：{} 不能为空", roleId, menuId);
            throw BizException.wrap(ExceptionCode.INVALID_OBJECT.getCode(),
                    ExceptionCode.INVALID_OBJECT.getMsg() + "roleId与menuId不能为空");
        }

        // 角色判断是否存在
        checkRoleIsExist(roleId);

        // 菜单资源判断是否存在
        checkMenuIsExist(menuId);

        // 幂等性判断
        PermissionPO permissionPODB = permissionMapper.selectOne(new LambdaQueryWrapper<PermissionPO>()
                .eq(PermissionPO::getRoleId, roleId)
                .eq(PermissionPO::getMenuId, menuId)
        );

        log.debug("从数据库中获取到：{}", permissionPODB);

        if (permissionPODB != null) {
            log.info("数据库中已经存在该记录，roleId：{} 与 menuId：{}", roleId, menuId);
            return;
        }

        insertPermission2DB(roleId, menuId);
    }

    private void insertPermission2DB(String roleId, String menuId) {
        // 插入数据库
        PermissionPO permissionPO = new PermissionPO();
        permissionPO.setMenuId(menuId);
        permissionPO.setRoleId(Integer.valueOf(roleId));
        log.info("权限表：{}", permissionPO);
        int insert = permissionMapper.insert(permissionPO);
        if (insert < 0) {
            log.error("插入权限失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "roleId: {}", roleId, "menuId：{}", menuId);
        }
    }

    private void checkMenuIsExist(String menuId) {
        MenuDTO menu = authorityMenuService.getMenu(menuId);
        if (menu == null) {
            log.error("{}不存在，请重新发送", menuId);
            throw BizException.wrap(ExceptionCode.DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    ExceptionCode.DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + menuId);
        }
    }

    private RolePO  checkRoleIsExist(String roleId) {
        RolePO rolePO = roleMapper.selectOne(new LambdaQueryWrapper<RolePO>().eq(RolePO::getId, roleId));
        if (rolePO == null) {
            log.error("{}不存在，请重新发送", roleId);
            throw BizException.wrap(ExceptionCode.DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    ExceptionCode.DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + roleId);
        }
        return rolePO;
    }

    @Transactional
    public void addMenAndChildMenuForRoleRecursion(String roleId, MenusDTO menusDTO) {
        // 递归结束
        if (menusDTO.getId() == null) {
            return;
        }

        // 添加当前权限
        addOneMenuForRole(roleId, menusDTO.getId());

        // 添加当前权限下子权限
        List<MenusDTO> menuDTOList = menusDTO.getMenuDTOList();
        for (MenusDTO dto : menuDTOList) {
            addMenAndChildMenuForRoleRecursion(roleId, dto);
        }
    }
}
